#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#include "get_input.h"
#include "global.h"

extern pthread_t run_tid;
pthread_mutex_t dir_mutex = PTHREAD_MUTEX_INITIALIZER;
int dir = 0;
const char * const DirI[] = { "UP", "Down", "Right", "Left" };

unsigned stack[High * Width];
int top = -1;
void push(int header) {
    stack[++top] = header;
}

void move(int dir) {
    int i;
    board[stack[0]] = '.';
    for(i=0; i<top; i++)
        stack[i] = stack[i+1];
    if(top>0) board[stack[top]] = SBODY;
    board[stack[top]+=dir] = SHEAD;
}

int score = 0;
int speed = 1000000;
void eat(int dir) {
    board[stack[top]] = SBODY; 
    push(stack[top]+dir);
    board[stack[top]] = SHEAD;
    score += (1000000/speed)*2;
}

void board_show(void) {
    int i,j;
    printf("\033[2J\n");
    printf("Score:%d\n", score);
    for(i=0; i<High; i++) {
        for(j=0; j<Width; j++)
            printf("%c  ", board[i*Width +j]);
        putchar('\n');
    }
    printf("\n\n");
    printf("%-5s", DirI[dir]);
    fflush(stdout);
}

int dirs[] = {-Width, Width, 1, -1};


void gen_food(void) {
    int food;
    do {
        food = rand() % (High*Width);
    }while(board[food] != '.');
    board[food] = SFOOD;
}



void *catch_mov(void *none) {
    int c;
    register_pquit_sig();
    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
    disable_terminal_return();
    while(1) {
        c = getchar();
        switch(c) {
        case 27:
            c = getchar();
            if(c == 91) {
                c = getchar();
                if(c>64 && c < 69) {
                    dir = c - 65;
                    pthread_mutex_lock(&dir_mutex);
                    printf("\10\10\10\10\10%-5s", DirI[dir]);
                    pthread_mutex_unlock(&dir_mutex);
                }
            }
            break;
        case 's':
        case 'S':
            pthread_kill(run_tid, SIGSUSPEND);
            printf("\nprint any key to go on\n");
            getchar();
            pthread_kill(run_tid, SIGRESUME);
            break;
        }
    }
}



pthread_t catch_tid;
void *run(void *none) {
    register_sus_sig();
    memset(board, '.', High*Width);
    srand(time(NULL));
    dir = rand() % 4;
    int header = (High+1)*Width/2;
    board[header] = SHEAD;
    top = -1;
    push(header);
    score = 0;
    gen_food();
    board_show();
    pthread_create(&catch_tid, NULL, catch_mov, NULL);
    while((header+=dirs[dir]) < High*Width && header >=0 ) {
        if((header%Width == 0 && dir == 2) || (header%Width == Width-1 && dir == 3))
            break;
        if(board[header] == SFOOD) {
            eat(dirs[dir]);
            gen_food();
        } else if(board[header] == '.'  ||  (header == stack[0] && top > 1))
            move(dirs[dir]);
        else break;
        pthread_mutex_lock(&dir_mutex);
        board_show();
        pthread_mutex_unlock(&dir_mutex);
        usleep(speed);
    }
    //pthread_kill(catch_tid, SIGPQUIT);
    pthread_cancel(catch_tid);
    pthread_join(catch_tid, (void **)NULL);
    printf("\n%s\n", "Game Over");  
    printf("YourScroe: %d\n", score);
    sleep(2);
    restore_terminal_settings();
    return NULL;
}
